/*
 * OREKIT-X
 * Copyright 2002-2008 CS Communication & Systemes
 * 
 * Parts of this software package have been licensed to CS
 * Communication & Systemes (CS) under one or more contributor license
 * agreements.  See the NOTICE file distributed with this work for
 * additional information.
 *  
 * This is an experimental copy of OREKIT from www.orekit.org.
 * Please use the original OREKIT from orekit.org for normal work
 * unrelated to this research project.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You
 * may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License.
 */
package ore.attitudes;

import ore.Attitude;
import ore.Frame;
import ore.PositionVelocity;
import ore.errors.OrekitException;
import ore.time.AbsoluteDate;

import org.apache.commons.math.geometry.Rotation;
import org.apache.commons.math.geometry.Vector3D;

/**
 * This class handles yaw compensation attitude law.
 * 
 * Yaw compensation is mainly used for Earth observation
 * satellites. As a satellites moves along its track, the image of
 * ground points move on the focal point of the optical sensor. This
 * motion is a combination of the satellite motion, but also on the
 * Earth rotation and on the current attitude (in particular if the
 * pointing includes Roll or Pitch offset).  In order to reduce
 * geometrical distortion, the yaw angle is changed a little from the
 * simple ground pointing attitude such that the apparent motion of
 * ground points is along a prescribed axis (orthogonal to the optical
 * sensors rows), taking into account all effects.
 * 
 * This attitude is implemented as a wrapper on top of an underlying
 * ground pointing law that defines the roll and pitch angles.
 * 
 * Instances of this class are immutable.
 *
 * @author V&eacute;ronique Pommier-Maurussane
 */
public class YawCompensation
    extends GroundPointingCompensating
{

    /** 
     * @param groundPointingLaw Ground pointing attitude law without
     * yaw compensation
     */
    public YawCompensation(GroundPointing groundPointingLaw) {
        super(groundPointingLaw);
    }


    /** 
     * Compute the system yaw compensation rotation at given date.
     * 
     * @param date Date when the system state shall be computed
     * @param pv Satellite position-velocity vector at given date in given frame.
     * @param base Base satellite attitude in given frame.
     * @param frame The frame in which satellite position-velocity an attitude are given.
     * 
     * @return yaw compensation rotation at date, i.e rotation between
     * non compensated attitude state and compensated state.
     * 
     * @throws OrekitException if some specific error occurs
     */
    public Rotation getCompensation(AbsoluteDate date, PositionVelocity pv,
                                    Attitude base, Frame frame)
        throws OrekitException
    {
        /* Compensation rotation definition :
         *   Z satellite axis is unchanged
         *   X satellite axis shall be aligned to target relative velocity
         */
        Vector3D satVelocity = pv.getVelocity();
        PositionVelocity targetPV = this.groundPointingLaw.getObservedGroundPoint(date, pv, frame);
        Vector3D targetVelocity = targetPV.getVelocity();
        Vector3D relativeVelocity = targetVelocity.subtract(satVelocity);
        /*
         * Create rotation transforming zsat to zsat and
         * relativeVelocity to -xsat
         */
        return new Rotation(Vector3D.PLUS_K, 
                            base.getRotation().applyTo(relativeVelocity),
                            Vector3D.PLUS_K, 
                            Vector3D.MINUS_I);
    }
    /**
     * Compute the yaw compensation angle at date.
     * 
     * @param date date when the system state shall be computed
     * @param pv satellite position-velocity vector at given date in given frame.
     * @param frame the frame in which satellite position-velocity is given.
     * 
     * @return Yaw compensation angle at date.
     * 
     * @throws OrekitException if some specific error occurs
     */
    public double getYawAngle(AbsoluteDate date, PositionVelocity pv, Frame frame)
        throws OrekitException
    {
        /*
         * Attitude rotation without yaw compensation
         */
        Rotation rotNoYaw = this.groundPointingLaw.getState(date, pv, frame).getRotation();
        /*
         * Attitude rotation without yaw compensation
         */
        Rotation rotYaw = this.getState(date, pv, frame).getRotation();
        /*
         * Compute yaw compensation angle by composition of both rotations
         */
        Rotation compoRot = rotYaw.applyTo(rotNoYaw.revert());

        return compoRot.getAngle();
    }

}
